/**
 * MeetingAgent class used to hold names and addresses along with
 * a message to be sent. It can be used to notify those attending
 * a meeting of the time arranged.
 * Once the agent has been set, the toString and fromString methods 
 * are used to send the agent, and recreate the agent once received.
 * @ author Francis and Aidan
 */

package agent;
import java.util.Vector;
import ap.Tokenizer;
import ap.NoSuchElementException;

public class InfoAgent implements Agent {
	private String agentType;
	private Vector contacts;    
	private Vector addresses;
	private String message;
	private int nextAddressIndex;

	/***************************************************
	 * chars used to read from and write to delimited 
	 */
	private static final char FIELD_DELIM     = '|';
	private static final char VALUE_DELIM     = '=';
	
	private static final char FIELD_NAME      = 'N';
	private static final char FIELD_ADDRESS   = 'A';
	private static final char FIELD_INDEX     = 'X';
	
	private static final char FIELD_MESSAGE   = 'M';
	/***************************************************
	 * constructor sets up vectors, agent type and nextAddressIndex
	 * attributed are entered either by UI or from string method
	 */
    public InfoAgent(){
    	agentType = Agent.TYPE_INFORMATION;
	 	contacts = new Vector();
		addresses = new Vector();
		nextAddressIndex = -1;//this will be updated to 0 the first time it is sent
	}
	/**************************************************************************
	 * access methods
	 */
	public String getType(){
		return this.agentType;
	}
	public int sizeOfContacts(){
		return this.contacts.size();
	}
	public int sizeOfAddresses(){
		return this.addresses.size();
	}	
	public String getContact(int n){
		return this.contacts.elementAt(n).toString();
	}
	public String getAddresses(int n){
		return this.addresses.elementAt(n).toString();
	}
	public String getMessage(){
		return this.message;
	}
	public int getNextAddressIndex(){
		return this.nextAddressIndex;
	}
	/**************************************************************************
	 * used to update the next destination
	 */
	public void incrementToNextAddress(){ 
		this.nextAddressIndex++;
	}
	/**************************************************************************
	 * methods to update meeting agent data
	 */
	public void addContact(String newContact, String newAddress){
		this.contacts.addElement (newContact);
		this.addresses.addElement(newAddress);
	}
	public void setMessage(String newMessage){
		this.message = newMessage;
	}
	/**************************************************************************
	 **************************************************************************
	 * read in all the agents values from a string
	 * the order in which they are read in is important and should 
	 * not be changed without also changing the toString function
	 * 
	 * @param agentString
	 */
	public void fromString(String agentString){
		String field, value;
		Tokenizer tokField = new Tokenizer(agentString, FIELD_DELIM);
		
		//first read in agent type
		//try {
		//	this.agentType = tokField.nextToken();
		//} catch (NoSuchElementException e) {
		//	System.err.println("NoSuchElementException caught in InfoAgent.fromString()");
		//	e.printStackTrace();
		//}
		//then read in all the agent values
		while( tokField.hasMoreTokens() ){			
			try {
				field = tokField.nextToken();
				value = field.substring(2);
				
				if( field.charAt(0) == FIELD_INDEX ){
					System.out.println("From string index: " + value);
					this.nextAddressIndex = Integer.parseInt(value);
				}
				else if( field.charAt(0) == FIELD_NAME ){					
					this.contacts.addElement(value);
				}
				else if( field.charAt(0) == FIELD_ADDRESS ){
					this.addresses.addElement(value);
				}
				else if( field.charAt(0) == FIELD_MESSAGE ){
					this.message = value;
				}

			} catch (NoSuchElementException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * the toString method writes out all the agents values 
	 * the order in which they are written out is important and should 
	 * be matched with the fromString method
	 * 
	 * @return the agent in string form
	 **/
	public String toString(){
		String agentString = new String();
		
		//first write out the agent type
		agentString += this.agentType;  	//	INFORMATION
		agentString += FIELD_DELIM;			//	|

		//then write out the nextAddressIndex
		agentString += FIELD_INDEX;			//	I
		agentString += VALUE_DELIM;			//	=		
		agentString += nextAddressIndex;	//  index
		agentString += FIELD_DELIM;			//	|
		
	
		//then write out all contact names and addresses in pairs
		for( int i=0; i<this.contacts.size(); i++ ){			
			agentString += FIELD_NAME;		//	N
			agentString += VALUE_DELIM;		//	=			
			agentString += this.contacts.elementAt(i);
			agentString += FIELD_DELIM;		//	|
			
			agentString += FIELD_ADDRESS;	//	A
			agentString += VALUE_DELIM;		//	=
			agentString += this.addresses.elementAt(i);
			agentString += FIELD_DELIM;		//	|
		}
		
		//then write out the message
		agentString += FIELD_MESSAGE;		//	M
		agentString += VALUE_DELIM;			//	=		
		agentString += message;				//  message
		agentString += FIELD_DELIM;			//	|
		
		return agentString;
	}
	/**************************************************************************
	 * return the next address this agent is to be sent to
	 * 
	 * @return valid address without port or empty string if not available
	 **/
	public String getNextAddress(){
		String nextAddress = "";
		if(nextAddressIndex < addresses.size()){
			nextAddress = addresses.elementAt(nextAddressIndex).toString();	
			Tokenizer tok = new Tokenizer(nextAddress, ":");
			try{
				nextAddress = tok.nextToken() + ":" + tok.nextToken() + ":";
			}catch(NoSuchElementException e){
				System.err.println("NoSuchElementException caught in MeetingAgent.getNextAddress()");
				e.printStackTrace();
			}			
		}
		else{
			System.err.println("nextAddressIndex is trying to access an address " +
					"that is not there in MeetingAgent.getNextAddress()");
		}
		
		
		System.err.println("InfoAgent.get next address: " + nextAddress);
		return nextAddress;
	}
	
	/**
	 * return the next port this agent is to be sent to
	 * 
	 * @return valid port or -1 if not available
	 */
	public int getNextPort(){
		String nextAddress = "";
		String port = "-1";		
		String token;	
		if(nextAddressIndex < addresses.size()){
			nextAddress = addresses.elementAt(nextAddressIndex).toString();	
			Tokenizer tok = new Tokenizer(nextAddress, ":");
			try{
				token = tok.nextToken() + ":" + tok.nextToken() + ":";				
				port = nextAddress.substring(token.length());
			}catch(NoSuchElementException e){
				System.err.println("NoSuchElementException caught in MeetingAgent.getNextPort()");
				e.printStackTrace();
			}
		}
		else{
			System.err.println("nextAddressIndex is trying to access an address " +
					"that is not there in MeetingAgent.getNextPort()");
		}
		
		
		System.err.println("InfoAgent.get next port: " + port);
		return Integer.parseInt(port);
	}
	/**
	 * return the next address and port this agent is to be sent to
	 * 
	 * @return valid address and port or empty string if not available
	 */
	public String getNextAddressPort(){
		String nextAddress = "";
		if(nextAddressIndex < addresses.size()){
			nextAddress = addresses.elementAt(nextAddressIndex).toString();
		}
		else{
			System.err.println("nextAddressIndex is trying to access an address " +
					"that is not there in MeetingAgent.getNextAddressPort()");
		}
		return nextAddress;
	}	
}
